var eyes=require('eyes');
var log=require('logging');

var scopelib=require('./scope');
var assert=require('./assertions');

var exp={
  send: function(scope)
  {
    var value=scope.value;
    var channel=scope.channel;
    var put=channel.put;
    var method;

    log('sending print: '+scope.print);

    log('sending', channel.put);
    method=scopelib.activate(scope, [channel.put], {});
    log('send method:', method);

    return ['comp', method, [value]];
  },

  arbre_return: function(scope)
  {
    return scope.value;
  },

  print: function(scope) {
    log('PRINT');
    eyes.inspect(scope.s);
    eyes.inspect(scope.s[1]);
  },

  add: function(scope) {
    log('add');
    eyes.inspect(scope);
    log(['literal', scope.a[1]+scope.b[1]]);
    return ['literal', scope.a[1]+scope.b[1]];
  },

  subtract: function(scope) {
    log('subtract');
    log(scope);
    eyes.inspect(scope);
    log(['literal', scope.a[1]-scope.b[1]]);
    return ['literal', scope.a[1]-scope.b[1]];
  },

  multiply: function(scope) {
    log(scope.a[1], '*', scope.b[1], '=', scope.a[1]*scope.b[1]);
    return ['literal', scope.a[1]*scope.b[1]];
  },

  divide: function(scope) {
    log('divide');
    eyes.inspect(scope);
    log(['literal', scope.a[1]/scope.b[1]]);
    return ['literal', scope.a[1]/scope.b[1]];
  },

  mod: function(scope) {
    log('mod');
    eyes.inspect(scope);
    log(['literal', scope.a[1]%scope.b[1]]);
    return ['literal', scope.a[1]%scope.b[1]];
  },

  arbre_and: function(scope) {
    log('and');
    eyes.inspect(scope);
    return ['literal', scope.a[1] && scope.b[1]];
  },

  arbre_or: function(scope) {
    log('or');
    eyes.inspect(scope);
    return ['literal', scope.a[1] || scope.b[1]];
  },

  arbre_not: function(scope) {
    log('not');
    eyes.inspect(scope);
    return ['literal', !scope.a[1]];
  },

  arbre_xor: function(scope) {
    log('xor');
    eyes.inspect(scope);
    return ['literal', (scope.a[1] ^ scope.b[1])==true]; // Use bitwise xor to get 1 or 0 and then coerce to boolean
  },

  lt: function(scope) {
    log('lt:', scope);
    return ['literal', scope.a[1]<scope.b[1]];
  },

  gt: function(scope) {
    log('gt:', scope);
    return ['literal', scope.a[1]>scope.b[1]];
  },

  eq: function(scope) {
    log(scope.a[1], '==', scope.b[1], '?', scope.a[1]==scope.b[1]);
    return ['literal', scope.a[1]===scope.b[1]];
  },

  set: function() {
  },

  also: function() {
  },

  applyContext: function() {
  },

  arbre_eval: function() {
  },

  when: function() {
  },

  arbre_if: function(scope) {
    var condition=scope.condition;
    var block;

    assert.exists(scope.condition);
    assert.exists(scope.thenBlock);
    assert.exists(scope.elseBlock);

    log('if', scope.condition[1]);

    if(scope.condition[1]===true)
    {
      block=scope.thenBlock;
    }
    else
    {
      block=scope.elseBlock;
    }

    log('block:', block);
    btype=block[0];
    log('btype:', btype);

    if(btype=='activeBlock')
    {
      bscope=block[1];
      log('bscope:', scopelib.pp(bscope));
      bf=block[2][1];
      log('bf:', bf);

      return ['comp', {
        scope: bscope,
	type: bf.type,
	params: bf.params,
	code: bf.code,
      }, []];
    }
    else if(btype=='literal') // Allow then and else clauses to be literals as well as blocks.
    {
      return block;
    }
  },

  arbre_foreach: function(scope) {
    assert.exists(scope.sym);
    assert.exists(scope.items);
    assert.exists(scope.block);

    var sym=scope.items[1];
    var items=scope.items[2];
    var block=scope.block[3];
    var results=[];

    log('for', items);
    log('block:', block);

    btype=block[0];
    log('btype:', btype);

    if(btype=='activeBlock')
    {
      bscope=block[1];
      log('bscope:', scopelib.pp(bscope));
      bf=block[2][1];
      log('bf:', bf);

      return ['comp', {
        scope: bscope,
	type: bf.type,
	params: bf.params,
	code: bf.code,
      }, []];
    }
    else if(btype=='literal') // Allow then and else clauses to be literals as well as blocks.
    {
      return block;
    }
  },

  arbre_for: function(scope) {
    assert.exists(scope.items);
    assert.exists(scope.block);

    var items=scope.items[1];
    var block=scope.block[1];
    var results=[];

    log('for', items);
    log('block:', block);

    btype=block[0];
    log('btype:', btype);

    if(btype=='activeBlock')
    {
      bscope=block[1];
      log('bscope:', scopelib.pp(bscope));
      bf=block[2][1];
      log('bf:', bf);

      return ['comp', {
        scope: bscope,
	type: bf.type,
	params: bf.params,
	code: bf.code,
      }, []];
    }
    else if(btype=='literal') // Allow then and else clauses to be literals as well as blocks.
    {
      return block;
    }
  },

  range: function(scope) {
    log('range');
    eyes.inspect(scope);

    var l=[];
    var x;
    for(x=scope.start[1]; x<scope.end[1]; x++)
    {
      l.push(x);
    }

    return ['literal', l];
  },



  write: function() {
  },

  time: function() {
  },

  arbre_with: function(scope) {
    var context=scope.context;
    var block=scope.block;
    var wscope;
    var btype;
    var bscope;
    var bcode;

    log('context:', context);
    log('block:', block);
    btype=block[0];
    log('btype:', btype);
    bscope=block[1];
    log('bscope:', scopelib.pp(bscope));
    bf=block[2][1];
    log('bf:', bf);

    wscope=scopelib.override(bscope, context[1]);

    return ['comp', {
      scope: wscope,
      type: bf.type,
      params: bf.params,
      code: bf.code,
      },
    []];
  }
}

for(key in exp)
{
  exports[key]=exp[key];
}

